# +----------------------------------------------------------------------
# | ChatWork智能聊天办公系统
# +----------------------------------------------------------------------
# | 软件声明: 本系统并非自由软件,未经授权任何形式的商业使用均属非法。
# | 版权保护: 任何企业和个人不允许对程序代码以任何形式任何目的复制/分发。
# | 授权要求: 如有商业使用需求,请务必先与版权所有者取得联系并获得正式授权。
# +----------------------------------------------------------------------
# | Author: ChatWork Team <2474369941@qq.com>
# +----------------------------------------------------------------------
from typing import List, Union
from fastapi import APIRouter, Request, UploadFile, Depends
from fastapi.responses import StreamingResponse
from starlette.responses import JSONResponse
from hypertext import R, response_json
from exception import AppException
from common.enums.errors import ErrorEnum
from common.chain.chain_server import ChatUtils
from apps.api.widgets.chat_robot_widget import ChatRobotWidget
from apps.api.schemas.index_schema import UploadResultVo
from apps.api.schemas.agent.chat import dialog_schema as schema
from apps.api.service.agent.chat.dialog_service import ChatDialogService


router = APIRouter(prefix="/dialog", tags=["对话接口"])


@router.get("$/v1/chat/history", summary="历史对话",
            response_model=R[List[Union[
                schema.ChatHistoryListVo.Question,
                schema.ChatHistoryListVo.Answer
            ]]])
@response_json
async def history(request: Request, params: schema.ChatHistorySearchIn = Depends()):
    publish_params = {
        "user_id": int(request.state.user_id),
        "publish_id": 0,
        "publish_uid": "",
        "publish_scene": ""
    }

    publish = await ChatDialogService.check_publish_api(request)
    if publish is not None:
        params.sid = 0
        params.bot = publish["bot"]
        publish_params["publish_id"] = publish["id"]
        publish_params["publish_uid"] = publish["identity"]
        publish_params["publish_scene"] = publish["scene"]
    else:
        if not publish_params["user_id"]:
            msgs = ErrorEnum.TOKEN_VALID.msg
            code = ErrorEnum.TOKEN_VALID.code
            raise AppException(msg=msgs, code=code)

    return await ChatDialogService.history(params, publish_params)


@router.post("$/v1/chat/clear", summary="清空对话", response_model=R)
@response_json
async def clear(request: Request, params: schema.ChatDialogClearIn):
    publish_params = {
        "user_id": int(request.state.user_id),
        "publish_id": 0,
        "publish_uid": "",
        "publish_scene": ""
    }

    publish = await ChatDialogService.check_publish_api(request)
    if publish is not None:
        params.sid = 0
        params.bot = publish["bot"].strip()
        publish_params["publish_id"] = publish["id"]
        publish_params["publish_uid"] = publish["identity"]
        publish_params["publish_scene"] = publish["scene"]
    else:
        if not publish_params["user_id"]:
            msgs = ErrorEnum.TOKEN_VALID.msg
            code = ErrorEnum.TOKEN_VALID.code
            raise AppException(msg=msgs, code=code)

    return await ChatDialogService.clear(params, publish_params)


@router.post("$/v1/publish/verify", summary="校验发布", response_model=R[schema.ChatPublishVerifyVo])
@response_json
async def verify(request: Request):
    publish = await ChatDialogService.check_publish_api(request)
    if publish is None:
        raise AppException("apiKey令牌缺失")
    return await ChatDialogService.verify(publish["bot"], publish["name"])


@router.post("$/v1/files/upload", summary="上传文件", response_model=R[UploadResultVo])
@response_json
async def upload(request: Request, file: UploadFile):
    publish_params = {
        "user_id": int(request.state.user_id),
        "publish_id": 0,
        "publish_uid": "",
        "publish_scene": ""
    }

    publish = await ChatDialogService.check_publish_api(request)
    if publish is not None:
        publish_params["publish_id"] = publish["id"]
        publish_params["publish_uid"] = publish["identity"]
        publish_params["publish_scene"] = publish["scene"]
    else:
        if not publish_params["user_id"]:
            msgs = ErrorEnum.TOKEN_VALID.msg
            code = ErrorEnum.TOKEN_VALID.code
            raise AppException(msg=msgs, code=code)

    user_id: int = int(request.state.user_id)
    return await ChatDialogService.upload(file, user_id, request.client.host)


@router.post("$/v1/chat/completions", summary="发起对话")
async def chat(request: Request, params: schema.ChatDialogSendIn):
    try:
        publish_id: int = 0
        publish_uid: str = "0"
        user_id: int = int(request.state.user_id)

        # 发布场景
        publish = await ChatDialogService.check_publish_api(request)
        if publish is not None:
            params.sid = 0
            params.bot = publish["bot"]
            params.scene = publish["scene"]
            publish_uid = publish["identity"]
            publish_id = publish["id"]

        # 对话构建
        chat_params = {
            "sid": params.sid,
            "bot": params.bot,
            "scene": params.scene,
            "stream": params.stream,
            "search": params.search,
            "messages": params.messages,
            "user_id": user_id,
            "publish_id": publish_id,
            "publish_uid": publish_uid,
            "ip": request.client.host
        }

        if params.stream:
            generate = ChatRobotWidget(request, chat_params).chat_sse()
            return StreamingResponse(generate, media_type="text/event-stream")
        return JSONResponse(await ChatRobotWidget(request, chat_params).chat_http())
    except Exception as e:
        code = e.code or 1
        error = e.msg if isinstance(e, AppException) else str(e)
        if params.stream:
            generate = ChatUtils.output_error(message=error, code=code)
            return StreamingResponse(generate, media_type="text/event-stream")
        return JSONResponse(ChatUtils.output_error(message=error, code=code, stream=False))
